#include <iostream>
#include <time.h>
#include <arpa/inet.h>
#include <termios.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <stdlib.h>

#include "dataDevice.h"
#include "unp.h"

using namespace std;

const char ConfigFile[]= "config";

int dataDevice::getFd() const
{
	return fd;
}

void dataDevice::setFd(int fd)
{
	this->fd = fd;
}

/*--------------------ethernetDataDevice-----------------*/
ethernetDataDevice::ethernetDataDevice(const char* addr, int port)
{
	this->addr = addr;
	this->port = port;
}

bool ethernetDataDevice::open()
{
	struct timeval timeout = {10, 0};
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == sockfd)
		return false;

	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
	setFd(sockfd);

	struct sockaddr_in dataDeviceAddr;
	dataDeviceAddr.sin_family = AF_INET;
	dataDeviceAddr.sin_port = htons(port);
	inet_pton(AF_INET, addr, &dataDeviceAddr.sin_addr);

	cout<<"Connect to datadevice "<<addr<<":"<<port<<endl;
	if(-1 == connect(sockfd, (struct sockaddr*)&dataDeviceAddr, sizeof(struct sockaddr)))
	{
		perror("ethernetDataDevice::open");
		return false;
	}

	cout<<"open ethernet device success."<<endl;
	return true;
}

ssize_t ethernetDataDevice::read(void *buffer, size_t size)
{
	cout<<"Device: Start reading"<<endl;
	int res = recv(getFd(), buffer, size, 0);
	if(-1 == res)
	{
		perror("ethernetDataDevice::read");
	}
	//cout<<"Device: read "<<res<<" bytes from device"<<endl;
	return res;
}

ssize_t ethernetDataDevice::write(void *buffer, size_t size)
{
	//char *data = static_cast<char *>(buffer);
	cout<<"Device write"<<endl;
	return send(getFd(), buffer, size, 0);
}

ethernetDataDevice::~ethernetDataDevice()
{
	int res = close(getFd());
	if(!res)
		cout<<"ethernetDataDevice::~ethernetDataDevice close socket success"<<endl;
	else
		cout<<"ethernetDataDevice::~ethernetDataDevice close socket fail"<<endl;
	cout<<"ethernetDataDevice::~ethernetDataDevice()"<<endl;
	setFd(-1);

}
/*-------------------serialDataDevice--------------------*/

bool setSpeed(int fd, int speed)
{
	struct termios opt;

	if(tcgetattr(fd, &opt) == -1)
	{
		cerr<<"tcgetattr error: "<<strerror(errno)<<endl;
		exit(1);
	}
	/*
	if(tcflush(fd, TCIOFLUSH) == -1)
	{
		cerr<<"tcflush error: "<<strerror(errno)<<endl;
		return false;
	}
	*/
	if(cfsetispeed(&opt, speed) == -1)
	{
		cerr<<"cfsetispeed error: "<<strerror(errno)<<endl;
		exit(1);
	}
	if(cfsetospeed(&opt, speed) == -1)
	{
		cerr<<"cfsetospeed error: "<<strerror(errno)<<endl;
		exit(1);
	}

	if(tcsetattr(fd, TCSANOW, &opt) == -1)
	{
		cerr<<"tcsetattr error: "<<strerror(errno)<<endl;
		exit(1);
	}
	if(tcflush(fd, TCIOFLUSH) == -1)
	{
		cerr<<"tcflush error: "<<strerror(errno)<<endl;
		exit(1);
	}

	return true;
}

bool set_data_format(int fd, int databits, int parity, int stopbits)
{
	//fcntl(fd, F_SETFL, 0);
	struct termios opt;

	if(tcgetattr(fd, &opt) == -1)
	{
		cerr<<"tcgetattr error: "<<strerror(errno)<<endl;
		return false;
	}

	opt.c_cflag &= ~CSIZE;

	switch(databits)
	{
		case 5:
			opt.c_cflag |= CS5;
			break;
		case 6:
			opt.c_cflag |= CS6;
			break;
		case 7:
			opt.c_cflag |= CS7;
			break;
		case 8:
			opt.c_cflag |= CS8;
			break;
		default:
			cerr<<"Unsupported data size"<<endl;
		return false;
	}

	switch(parity)
	{
		case 'n':
		case 'N':
			opt.c_cflag &= ~PARENB;
			opt.c_iflag &= ~INPCK;
			break;
		case 'o':
		case 'O':
			opt.c_cflag |= (PARODD|PARENB);
			opt.c_iflag |= INPCK;
			break;
		case 'e':
		case 'E':
			opt.c_cflag |= PARENB;
			opt.c_cflag &= ~PARODD;
			opt.c_iflag |= INPCK;
			break;
		default:
			cerr<<"Unsupported parity"<<endl;
		return false;
	}

	switch(stopbits)
	{
		case 1:
			opt.c_cflag &= ~CSTOPB;
			break;
		case 2:
			opt.c_cflag |= ~CSTOPB;
			break;
		default:
			cerr<<"Unsupported stop bits"<<endl;
		return false;
	}

	/* Set input parity option */
	if(parity != 'n' && parity != 'N')
		opt.c_iflag |= INPCK;

	opt.c_cflag |= (CLOCAL | CREAD);
	/*
	opt.c_cc[VTIME] = 1; //0.1 seconds
	opt.c_cc[VMIN] = 10;
	*/

	//opt.c_lflag |= (ICANON | ECHO | ECHOE);
	opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

	if(tcsetattr(fd, TCSANOW, &opt) == -1)
	{
		cerr<<"tcsetattr error: "<<strerror(errno)<<endl;
		return false;
	}

	if(tcflush(fd, TCIFLUSH) == -1)	/* Update the options and do it Now*/
	{
		cerr<<"tcflush error: "<<strerror(errno)<<endl;
		return false;
	}

	Fcntl(fd, F_SETFL, 0);
	return true;
}

serialDataDevice::serialDataDevice(const char* serialName, string speed)
{
	this->serialName = serialName;
	this->speed = speed;
	cout<<"SerialName: "<<serialName<<endl
	    <<"speed: "<<speed<<endl;
}

bool serialDataDevice::open()
{
	int fd = ::open(serialName, O_RDWR | O_NOCTTY);
	if(fd == -1)
	{
		perror("serialDataDevice::open open");
		return false;
	}

	setFd(fd);

	struct termios opt; 
	int res;

	res = tcgetattr(getFd(), &opt);
	if(res == -1)
	{
		perror("serialDataDevice::open tcgetattr");
		return false;
	}
	if(speed == "57600")
	{
		cfsetispeed(&opt, B57600);
		cfsetospeed(&opt, B57600);
	}
	else if(speed == "115200")
	{
		cfsetispeed(&opt, B115200);
		cfsetospeed(&opt, B115200);
	}

	opt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
	opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
	opt.c_oflag &= ~(OPOST);
	opt.c_cflag &= ~(CSIZE | PARENB);
	opt.c_cflag |= CS8;

	opt.c_cc[VMIN] = 30; 
	opt.c_cc[VTIME] = 5;

	tcsetattr(getFd(), TCSANOW, &opt);

	return true;
}

ssize_t serialDataDevice::read(void *buffer, size_t size)
{
	return Read(getFd(), buffer, size);
}

ssize_t serialDataDevice::write(void *buffer, size_t size)
{
	Write(getFd(), buffer, size);
	return size;
}

serialDataDevice::~serialDataDevice()
{
	cout<<"Close serial device"<<endl;
	Close(getFd());
}
